import { setOptions } from "leaflet";

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null;
  }
  const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
  let date;
  if (typeof time === "object") {
    date = time;
  } else {
    if (typeof time === "string") {
      if (/^[0-9]+$/.test(time)) {
        // support "1548221490638"
        time = parseInt(time);
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), "/");
      }
    }

    if (typeof time === "number" && time.toString().length === 10) {
      time = time * 1000;
    }
    date = new Date(time);
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay(),
  };
  const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key];
    // Note: getDay() returns 0 on Sunday
    if (key === "a") {
      return ["日", "一", "二", "三", "四", "五", "六"][value];
    }
    return value.toString().padStart(2, "0");
  });
  return time_str;
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (("" + time).length === 10) {
    time = parseInt(time) * 1000;
  } else {
    time = +time;
  }
  const d = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;

  if (diff < 30) {
    return "刚刚";
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + "分钟前";
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + "小时前";
  } else if (diff < 3600 * 24 * 2) {
    return "1天前";
  }
  if (option) {
    return parseTime(time, option);
  } else {
    return (
      d.getMonth() +
      1 +
      "月" +
      d.getDate() +
      "日" +
      d.getHours() +
      "时" +
      d.getMinutes() +
      "分"
    );
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
  if (!search) {
    return {};
  }
  const obj = {};
  const searchArr = search.split("&");
  searchArr.forEach((v) => {
    const index = v.indexOf("=");
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

export const debounce = (fn, time) => {
  let timeout;

  const debouncedFunction = function (...args) {
    const context = this;
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fn.apply(context, args);
      timeout = null;
    }, time);
  };

  debouncedFunction.cancel = function () {
    if (timeout) {
      clearTimeout(timeout);
    }
  };

  return debouncedFunction;
};

export const optionsMerger = (props, instance) => {
  const options =
    instance.options && instance.options.constructor === Object
      ? instance.options
      : {};
  props = props && props.constructor === Object ? props : {};
  const result = collectionCleaner(options);
  props = collectionCleaner(props);
  const defaultProps = instance.$options.props;
  for (const key in props) {
    const def = defaultProps[key]
      ? defaultProps[key].default &&
        typeof defaultProps[key].default === "function"
        ? defaultProps[key].default.call()
        : defaultProps[key].default
      : Symbol("unique");
    let isEqual = false;
    if (Array.isArray(def)) {
      isEqual = JSON.stringify(def) === JSON.stringify(props[key]);
    } else {
      isEqual = def === props[key];
    }
    if (result[key] && !isEqual) {
      console.warn(
        `${key} props is overriding the value passed in the options props`
      );
      result[key] = props[key];
    } else if (!result[key]) {
      result[key] = props[key];
    }
  }
  return result;
};

export const collectionCleaner = (options) => {
  const result = {};
  for (const key in options) {
    const value = options[key];
    if (value !== null && value !== undefined) {
      result[key] = value;
    }
  }
  return result;
};

export const propsBinder = (vueElement, leafletElement, props, options) => {
  for (const key in props) {
    const setMethodName = "set" + capitalizeFirstLetter(key);
    const deepValue =
      props[key].type === Object ||
      props[key].type === Array ||
      Array.isArray(props[key].type);
    if (props[key].custom && vueElement[setMethodName]) {
      vueElement.$watch(
        key,
        (newVal, oldVal) => {
          vueElement[setMethodName](newVal, oldVal);
        },
        {
          deep: deepValue,
        }
      );
    } else if (setMethodName === "setOptions") {
      vueElement.$watch(
        key,
        (newVal, oldVal) => {
          setOptions(leafletElement, newVal);
        },
        {
          deep: deepValue,
        }
      );
    } else if (leafletElement[setMethodName]) {
      vueElement.$watch(
        key,
        (newVal, oldVal) => {
          leafletElement[setMethodName](newVal);
        },
        {
          deep: deepValue,
        }
      );
    }
  }
};

export const capitalizeFirstLetter = (string) => {
  if (!string || typeof string.charAt !== "function") {
    return string;
  }
  return string.charAt(0).toUpperCase() + string.slice(1);
};

export const findRealParent = (firstVueParent) => {
  let found = false;
  while (firstVueParent && !found) {
    if (firstVueParent.mapObject === undefined) {
      firstVueParent = firstVueParent.$parent;
    } else {
      found = true;
    }
  }
  return firstVueParent;
};

export function linearInterpolation(start, end, count) {
  if (count < 0) throw new Error("插值点数量不能为负数");
  if (count === 0) return [start, end];

  const step = (end - start) / (count + 1);
  const result = [start];

  for (let i = 1; i <= count; i++) {
    result.push(start + step * i);
  }

  result.push(end);
  return result;
}

export const forEach = (list, callback) => [].forEach.call(list, callback);

export const treeFilter = (tree, func) => {
  return tree
    .map((node) => ({ ...node }))
    .filter((node) => {
      node.children = node.children && treeFilter(node.children, func);
      return func(node) || (node.children && node.children.length);
    });
};

export const treeFind = (tree, func) => {
  for (const data of tree) {
    if (func(data)) return data;
    if (data.children) {
      const res = treeFind(data.children, func);
      if (res) return res;
    }
  }
  return null;
};

// 截取前两个英文单词的首字母
export function getFirstLettersOfFirstTwoWords(str) {
  // 使用正则表达式匹配英文单词（非字母开头或非字母结尾的字符将被忽略）
  const words = str.match(/\b[A-Za-z]+/g);

  // 检查是否有足够的单词
  if (words && words.length >= 2) {
    // 获取前两个单词的首字母
    return words[0][0] + words[1][0];
  } else {
    // 如果单词数量不足两个，返回空字符串或适当的错误信息
    return "";
  }
}

export function getTextWith(text, fontStyle) {
  var canvas = document.createElement("canvas");
  var context = canvas.getContext("2d");
  context.font =
    fontStyle || "16px  Arial, PingFang SC, PingFang SC Regular, sans-serif"; // 设置字体样式
  var dimension = context.measureText(text);
  return dimension.width;
}

export function normalizeData(data, field) {
  if (field) {
    const min = Math.min(...data.map(d => d[field]));
    const max = Math.max(...data.map(d => d[field]));
    return data.map((value) => ({
        ...value,
        v1: (value[field] - min) / (max - min)
    }));
  } else {
    const min = Math.min(...data);
    const max = Math.max(...data);
    return data.map((value) => (value - min) / (max - min));
  }
}
